#ifndef ODUPDATERSDK_LIBRARY_H
#define ODUPDATERSDK_LIBRARY_H

class ODUpdater;

#include <string>
#include <list>
#include <atomic>
#include "config/handler/IUpdateHandler.h"
#include "config/proceessing/search/IResSearchProcessor.h"
#include "config/proceessing/record/IUpdateRecorder.h"
#include "config/log/BasisLogger.h"
#include "config/server_api/IUpdaterServer.h"
#include "config/proceessing/file/IFileProcessor.h"
#include "config/transmit/IStreamTransmit.h"
#include "thread/ThreadPool.h"
#include "config/proceessing/record/IUpdateRecorder.h"

using namespace std;

/*
 初梦更新器-第二代-sdk
 主要使用http/https协议实现功能

    版本：C++17
    sdk版本：1.0
    其他依赖：nlohmann_json,libcurl
    开源协议：LGPL
    作者：ming_za
    QQ：2510674200

 此类为更新程序入口
 */
class ODUpdater{
private:
    //更新器服务器ip
    string ip;
    //更新器未发布版本密钥，不使用时设为0即可
    int unpublishKey;
    //标签id
    int64_t labelId;
    //请求协议
    string reqProtocol = "http";
    //更新器生命周期监听
    IUpdateHandler *updateHandler;
    //资源检索处理器
    IResSearchProcessor *resSearchProcessor;
    //更新服务器API
    IUpdaterServer *updaterServer;
    //文件处理器
    IFileProcessor *fileProcessor;
    //文件工具
//    FileUtils *fileUtils;
     //更新记录器
    IUpdateRecorder *updateRecorder;
    //更新资源的根目录
    string rootDirectory;
    //日志
    BasisLogger *logger;
    //更新错误列表
    list<UpdateError> errorList{};
    //流传输接口
    IStreamTransmit *streamTransmit;

    //更新开启标签
    bool isStart = false;
    //更新停止标签
    bool stop = true;
    //原子任务结束计数器，包括出错任务
    atomic<int> endUpdateCount = 0;
    //线程池
    ThreadPool *consumerThreadPool = nullptr;
    //更新生产者线程
    thread updateProducer{};

    //生产者线程锁
    mutex produceMutex;
    condition_variable produceCondition;

    //任务线程锁
    mutex taskMutex{};
    condition_variable taskCondition;

    bool update();

    void tryModifyConfig() const;
public:

    ODUpdater(string ip, int unpublishKey, int64_t labelId, IUpdateHandler *updateHandler,
              IResSearchProcessor *resSearchProcessor, IUpdaterServer *updaterServer, IFileProcessor *fileProcessor,
              IUpdateRecorder *updateRecorder, BasisLogger *logger,
              IStreamTransmit *streamTransmit, string rootDirectory);

    static ODUpdater createUpdater(const string &ip,int64_t labelId,int unpublishKey,const string &rootDir);

    static ODUpdater createUpdater(const string &ip,int64_t labelId);

    static ODUpdater createUpdater(const string &ip,int64_t labelId,const string &rootDirectory);
    /**
     * 开启更新
     * <p> 逐个版本更新，并发下载只在同一个版本多个资源中有效。
     * <p> 每个版本需要等上一个版本更新完成时再更新，避免意外断开导致资源混乱。
     * <p> 更新将以异步开启，可以调用odUpdater.awaitUpdate()等待更新完成。不要在更新完成前清除ODUpdater对象，否则无法正常运行
     *
     * <p>异常处理：
     * <p> 当某个更新出现异常时，暂停新的更新产生。
     * <p> 更新池的所有更新结束时直接跳出版本循环，不调用IUpdateHandler.updateDoneVersion()
     * <p> 最后将错误信息传递给IUpdateHandler.allUpdateComplete()，可通过调用UpdateCompleteEvent. hasError()判断是否出现异常。
     * @return 存在更新，而且更新启动时返回true，不存在更新则返回false
     */
    bool startUpdate() noexcept(false);

    [[nodiscard]] const string &getIp() const;

    [[nodiscard]] int getUnpublishKey() const;

    [[nodiscard]] int64_t getLabelId() const;

    [[nodiscard]] const string &getReqProtocol() const;

    [[nodiscard]] IUpdateHandler *getUpdateHandler() const;

    [[nodiscard]] IResSearchProcessor *getResSearchProcessor() const;

    [[nodiscard]] IUpdateRecorder *getUpdateRecorder() const;

    [[nodiscard]] const string &getRootDirectory() const;

    [[nodiscard]] list<UpdateError> getErrorList() const;

    [[nodiscard]] BasisLogger *getLogger() const;

    [[nodiscard]] IStreamTransmit *getStreamTransmit() const;

    [[nodiscard]] IUpdaterServer *getUpdaterServer() const;

    [[nodiscard]] IFileProcessor *getFileProcessor() const;

    void setIp(const string &ip);

    void setUnpublishKey(int unpublishKey);

    void setLabelId(int64_t labelId);

    void setReqProtocol(const string &reqProtocol);

    void setUpdateHandler(IUpdateHandler *updateHandler);

    void setResSearchProcessor(IResSearchProcessor *resSearchProcessor);

    void setUpdaterServer(IUpdaterServer *updaterServer);

    void setFileProcessor(IFileProcessor *fileProcessor);

    void setUpdateRecorder(IUpdateRecorder *updateRecorder);

    void setRootDirectory(const string &rootDirectory);

    void setLogger(BasisLogger *logger);

    void setStreamTransmit(IStreamTransmit *streamTransmit);

    void awaitOneTaskDone();

    void addEndTask();

    void reducePoolSize();

    void addUpdateError(const UpdateError &error);

    //等待更新结束
    void awaitUpdate();
    //终止更新
    void shutdown();

    bool isStartUpdate() const;

    virtual ~ODUpdater();
};

#endif //ODUPDATERSDK_LIBRARY_H
